﻿using CleanArchitecture.Core.Configuration;
using CleanArchitecture.Core.Events;
using CleanArchitecture.Core.Handlers;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Infrastructure.Entities;
using CleanArchitecture.Infrastructure.Entities.Business;
using CleanArchitecture.Infrastructure.Interfaces;
using CleanArchitecture.Infrastructure.Interfaces.Business;
using CleanArchitecture.Infrastructure.Models.Business.Comments;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CleanArchitecture.Infrastructure.Services.Business
{
    public partial class CommentService : ICommentService
    {
        #region Fields
        private readonly IDomainEventDispatcher _eventDispatcher;
        private readonly IRepository<Comment> _commentRepository;
        #endregion

        #region Ctor
        public CommentService(IDomainEventDispatcher eventDispatcher,
            IRepository<Comment> commentRepo)
        {
            this._eventDispatcher = eventDispatcher;
            this._commentRepository = commentRepo;
        }
        #endregion

        /// <summary>
        /// Gets all Comment Items by page 
        /// 留言和回复在同一张表，笼统查询会使回复数据占用留言查询数量，当回复时间滞后可能会使分页数据中不包含回复信息 或 分页数据留言不够一页查询数量
        /// </summary>
        /// <returns></returns>
        public IViewPagedList<Comment> GetCommentItemsByPage(CommentSearchModel searchModel)
        {
            var commentQuery = _commentRepository.TableNoTracking;
            commentQuery = commentQuery.Where(n => n.CommentType == searchModel.CommentType && n.EntityId == searchModel.EntityId && n.IsActive == EntityEnumConfig.YesorNo.YES && n.CommentIsResponsed == searchModel.CommentIsResponsed)
                         .OrderByDescending(n => n.CreatedOnTimeUtc);
            var comments = new ViewPagedList<Comment>(commentQuery, searchModel.Page - 1, searchModel.PageSize);
            //分页查询按分页命中查询数据后，再根据分页留言数据查询所有回复数据
            if(searchModel.CommentIsResponsed == EntityEnumConfig.YesorNo.YES && comments != null)
            {
                var responseQuery = _commentRepository.TableNoTracking;
                int[] rootIds = comments.Select(c => c.Id).ToArray();
                responseQuery = responseQuery.Where(r => r.IsActive == EntityEnumConfig.YesorNo.YES && rootIds.Contains(r.RootId) && r.RootId != r.Id && r.CommentType == searchModel.CommentResponseType);
                comments.AddRange(responseQuery.ToList());
            }
            return comments;
        }

        public Comment GetCommentEntityById(int entityId)
        {
            if (entityId == 0) return null;
            return _commentRepository.GetById(entityId);
        }

        public virtual void AddCommentResponse(Comment comment, Comment response)
        {
            if (comment == null || response == null) 
                throw new ArgumentNullException("comment or response");
            //a little tip here comment for update response for add
            //use Efcore update for entity insert
            IList<Comment> entities = new List<Comment>();
            entities.Add(comment);
            entities.Add(response);
            _commentRepository.Update(entities);
            if(!string.IsNullOrEmpty(response.SysLogMsg))
                _eventDispatcher.Dispatch(new EntityInsertedEvent<Comment>(response));
            entities.Clear();
        }

        public virtual void DeleteComment(Comment entity)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));
            List<Comment> commentanditsResponses = new List<Comment>();
            commentanditsResponses.Add(entity);
            if(entity.CommentIsResponsed == EntityEnumConfig.YesorNo.YES)
            {
                var responses = _commentRepository.Table
                                    .Where(c => c.RootId == entity.Id && c.RootId != c.Id && c.IsActive == EntityEnumConfig.YesorNo.YES).ToList();
                commentanditsResponses.AddRange(responses);
            }
            foreach(var cmt in commentanditsResponses)
            {
                cmt.IsActive = EntityEnumConfig.YesorNo.No;
                cmt.CommentTitle = string.IsNullOrEmpty(cmt.CommentTitle)
                                 ? "Deleted"
                                 : "Deleted-" + cmt.CommentTitle;
            }
            _commentRepository.Update(commentanditsResponses);
            if (!string.IsNullOrEmpty(entity.SysLogMsg))
                _eventDispatcher.Dispatch(new EntityDeletedEvent<Comment>(entity));
            commentanditsResponses.Clear();

        }
    }
}
